import { track, trigger, effect } from "./effect.mjs";

export function reactive(obj) {
  return new Proxy(obj, {
    get(target, p) {
      track(...arguments);
      let value = Reflect.get(...arguments);
      if (value !== null && typeof value === "object") {
        return reactive(value);
      }
      return value;
    },
    set(target, p, value) {
      let oldValue = Reflect.get(...arguments);
      if (oldValue === value) {
        return value;
      }
      let newValue = Reflect.set(...arguments);
      trigger(...arguments);
      return newValue;
    },
  });
}

export function ref(value) {
  return reactive({ value: value });
}

function getterEff(computedRef, eff) {
	effect(() => {
		computedRef.value = eff();
	});
}

function setterEff(computedRef, eff) {
	effect(() => {
		eff(computedRef.value);
	});
}

export function computed(eff) {
	let result = ref(null);
	if (typeof eff === "function") {
		getterEff(result, eff);
	} else {
		getterEff(result, eff.get);
		setterEff(result, eff.set);
	}
	return result;
}

export function watchEffect(cb) {
	let e = effect(cb);
	return e.stop.bind(e);
}

export function watch(getter, cb) {
	// 两个关键点，一个是将getter作为reactiveEffect本体，一个是oldValue闭包
  let oldValue;

  let job = () => {
    let newVal = e.run();
    cb(newVal, oldValue);
    oldValue = newVal;
  };
  // 注意 effect 的本体是 getter，
  // 也就是说只有 getter 可以触发依赖收集
  // 而 job 将作为 scheduler 传入
  let e = effect(getter, job);
  // 首次运行，完成第一个旧值的获取
  oldValue = e.run();
  // 与 watchEffect 一样返回 stop 函数
  return e.stop.bind(e);
}
